package cn.bonoon.kernel.security;

import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import cn.bonoon.entities.PrivilegeEntity;
import cn.bonoon.kernel.menus.ChannelDefinition;
import cn.bonoon.kernel.menus.ItemableDefinition;
import cn.bonoon.kernel.menus.MenuDefinition;
import cn.bonoon.kernel.menus.MenuableDefinition;
import cn.bonoon.kernel.menus.ModuleDefinition;
import cn.bonoon.kernel.menus.ModuleManager;
import cn.bonoon.kernel.menus.TabItemDefinition;
import cn.bonoon.kernel.menus.TabsDefinition;
import cn.bonoon.kernel.menus.privileges.PrivilegeInspector;
import cn.bonoon.policy.AccountPrivilegePolicy;

/**
 * 用来缓存已经登录的用户的权限信息
 * @author jackson
 *
 */
public class LogonUserPrivilegeMapped {
	
	private final ModuleManager moduleManager;
	
	private final Map<String, LogonUserPrivilegeItem> items = new HashMap<>();
	/** 所有当前用户可以访问的子系统 */
	private final Set<String> modules = new HashSet<>();
	/** 所有当前用户可访问的频道；但如果这个频道本身是有功能的，则该用户不一定能访问上面的功能 */
	private final Set<String> channels = new HashSet<>();
	
	/** 系统默认的模块，也就是说系统登录成功后默认进入的子系统 */
	private ModuleDefinition defaultModule;
	
	class LogonUserPrivilegeItem{
		final String id;
		String name;
		long action;
		
		LogonUserPrivilegeItem(String id){
			this.id = id;
		}

		LogonUserPrivilegeItem(String id, long action){
			this(id);
			this.action = action;
		}
		

		LogonUserPrivilegeItem(String id, String name){
			this(id);
			this.name = name;
		}
		
	}
	
	private long lastUpdate;
	
	private final Object source;
	
	private final AccountPrivilegePolicy policy;
	
	private long usedCount;
	
	public LogonUserPrivilegeMapped(ModuleManager moduleManager, Object source, AccountPrivilegePolicy policy){
		this.moduleManager = moduleManager;
		this.source = source;
		this.policy = policy;
	}
	
	public void update(){
		this.lastUpdate = System.currentTimeMillis();
	}
	
	public LogonUserPrivilegeMapped visit(){
		usedCount++;
		return this;
	}
	
	public Object getSource() {
		return source;
	}
	
	public long getUsedCount() {
		return usedCount;
	}
	
	public AccountPrivilegePolicy getPolicy() {
		return policy;
	}
	
	private void internalAdd(String id, String name){
		
		ItemableDefinition it = moduleManager.find(id);
		
		if(it == null) return;
		
		if(null == defaultModule) defaultModule = it.getModule();
		
		modules.add(it.getModule().getId());
		channels.add(it.getChannel().getId());
		
		items.put(it.getId(), new LogonUserPrivilegeItem(it.getId(), name));
	}
	
	/** 注意：id不能加密 */
	public void add(String id, String name){
		internalAdd(id, name);
	}
	
	public void add(PrivilegeEntity pr){
		modules.add(pr.getModuleId());
		channels.add(pr.getChannelId());
		
		String mid = pr.getMeunId();
		LogonUserPrivilegeItem item = items.get(mid);
		if(null == item){
			items.put(mid, new LogonUserPrivilegeItem(mid, pr.getActions()));
		}else{
			item.action = item.action | pr.getActions();
		}
		
		if(null == defaultModule){
			defaultModule = moduleManager.module(pr.getModuleId());
		}
	}
	
	public void all(){
		privilege = PrivilegeInspector.ALL;
	}
	
	public long getLastUpdate() {
		return lastUpdate;
	}

	public List<Long> getActions(MenuableDefinition item) {
		LogonUserPrivilegeItem lupItem = items.get(item.getId());
		if(null != lupItem && lupItem.action > 0){
			return Collections.singletonList(lupItem.action);
		}
		return Collections.emptyList();
	}
	
	private PrivilegeInspector privilege = new InternalPrivilegeInspector();
	
	private class InternalPrivilegeInspector implements PrivilegeInspector{
	
//	private final PrivilegeInspector privilege = new PrivilegeInspector() 
			
		@Override
		public boolean hasPrivilege(ChannelDefinition item) {
			return channels.contains(item.getId());
		}
		
		@Override
		public boolean hasPrivilege(TabItemDefinition item) {
			return items.containsKey(item.getId());
		}
		
		@Override
		public boolean hasPrivilege(TabsDefinition item) {
			return items.containsKey(item.getId());
		}
		
		@Override
		public boolean hasPrivilege(MenuableDefinition item) {
			return items.containsKey(item.getId()) || channels.contains(item.getId());
		}
		
		@Override
		public boolean hasPrivilege(MenuDefinition item) {
			return items.containsKey(item.getId());
		}
	};

	public PrivilegeInspector privilege(MenuableDefinition item) {
		return privilege;
	}

	public PrivilegeInspector privilege(ModuleDefinition module) {
		return privilege;
	}

	public PrivilegeInspector privilege(TabsDefinition tab) {
		return privilege;
	}

	public PrivilegeInspector privilege(String mid, String cid) {
		return privilege;
	}

	public ModuleDefinition getDefaultModule() {
		return defaultModule;
	}
}
